package com.ruoyi.flow.common.tools.fastdfs;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.IOException;

/**
 * 对象池
 *
 * @see GenericObjectPool
 */
public class TrackerServerPool {
    private static final Logger LOGGER = LoggerFactory.getLogger(TrackerServerPool.class);
    private GenericObjectPool<TrackerServer> pool;

    private TrackerServerPool(GenericObjectPool<TrackerServer> pool) {
        this.pool = pool;
    }

    /**
     * 从对象池里获取对象
     *
     * @return
     */
    public TrackerServer takeTrackerServer() {
        pool = checkNotNull(pool);
        try {
            TrackerServer trackerServer = pool.borrowObject();
            LOGGER.info("take trackServer <{}> from pool <{}>", trackerServer.toString(), pool.toString());
            return trackerServer;
        } catch (Exception e) {
            LOGGER.error("take trackerServer error", e);
        }
        return null;
    }

    /**
     * 将对象归还到对象池
     *
     * @param trackerServer
     */
    public void returnTrackServer(TrackerServer trackerServer) {
        if (trackerServer != null) {
            LOGGER.info("return trackServer <{}> to pool <{}>", trackerServer.toString(), pool.toString());
            this.pool.returnObject(trackerServer);
        }
    }


    public static Builder builder() {
        return new Builder();
    }

    static class Builder {
        /**
         * 最大对象数
         */
        private int maxPoolSize = 30;
        /**
         * 最小对象数
         */
        private int minPoolSize = 10;
        /**
         * 线程等待时间，时间毫秒。超出跑出异常
         */
        private long waitTime = 200000;

        public static final String CONFIG_PATH = FdfsOperator.class.getResource("/").getPath() + "/conf/fdfs_client.conf";

        /**
         * 设置最大对象数
         *
         * @param maxPoolSize
         * @return
         */
        public Builder maxPoolSize(int maxPoolSize) {
            this.maxPoolSize = maxPoolSize;
            return this;
        }

        /**
         * 设置最小对象数
         *
         * @param minPoolSize
         * @return
         */
        public Builder minPoolSize(int minPoolSize) {
            this.minPoolSize = minPoolSize;
            return this;
        }

        /**
         * 设置等待时间
         *
         * @param waitTime
         * @return
         */
        public Builder waitTime(long waitTime) {
            this.waitTime = waitTime;
            return this;
        }

        public int getMaxPoolSize() {
            return maxPoolSize;
        }

        public int getMinPoolSize() {
            return minPoolSize;
        }

        public long getWaitTime() {
            return waitTime;
        }

        public TrackerServerPool build() {
            //设置对象池参数
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            config.setMaxTotal(this.getMaxPoolSize());
            config.setMaxIdle(this.getMaxPoolSize());
            config.setMinIdle(this.getMinPoolSize());
            config.setMaxWaitMillis(this.getWaitTime());

            //初始化FastDFS
            try {
                ClientGlobal.init(CONFIG_PATH);
            } catch (IOException e) {
                LOGGER.error("FastDFS init error.", e);
            } catch (Exception e) {
                LOGGER.error("FastDFS init error.", e);
            }

            GenericObjectPool<TrackerServer> pool = new GenericObjectPool<TrackerServer>(new BasePooledObjectFactory<TrackerServer>() {
                @Override
                public TrackerServer create() throws Exception {
                    LOGGER.info("create trackerServer Object to pool...");
                    TrackerServer trackerServer = null;
                    try {
                        TrackerClient trackerClient = new TrackerClient();
                        trackerServer = trackerClient.getConnection();
                    } catch (IOException e) {
                        LOGGER.error("create TrackServer failed.", e);
                        trackerServer.close();
                    }
                    return trackerServer;

                }

                @Override
                public PooledObject<TrackerServer> wrap(TrackerServer t) {
                    t = checkNotNull(t);
                    return new DefaultPooledObject<TrackerServer>(t);
                }

                @Override
                public void destroyObject(PooledObject<TrackerServer> p) throws Exception {
                    p = checkNotNull(p);
                    TrackerServer trackerServer = p.getObject();
                    if (trackerServer != null) {
                        trackerServer.close();
                        LOGGER.info("destroyed trackerServer:" + trackerServer.toString());
                    }
                }

                @Override
                public boolean validateObject(PooledObject<TrackerServer> p) {
                    p = checkNotNull(p);
                    TrackerServer trackerServer = p.getObject();
                    boolean flag = false;
                    try {
                        flag = ProtoCommon.activeTest(trackerServer.getSocket());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return flag;
                }
            }, config);

            pool.setTestOnBorrow(true);

            return new TrackerServerPool(pool);
        }
    }
}
